﻿
#ifndef QSS_H
#define QSS_H

#include <QWidget>
#include <QMainWindow>
#include <QDialog>
#include <QMessageBox>
#include <QFrame>
#include <QDockWidget>
#include <QPushButton>
#include <QAbstractNativeEventFilter>
#include <QDebug>

#include "ui_qsstoast.h"
#include "ui_process.h"

#ifdef __MINGW32__
#include "windows.h"
#include "winuser.h"
#pragma comment(lib, "libuser32.a")
#endif

class QPushButton;
class QLabel;
class QMouseEvent;
#define STANDARD_DPI 96.0
#define WM_DPICHANGED 0x02e0


typedef enum{
    RA_Resize = 1,
    RA_FixedWidth = 2,
    RA_FixedHeight = 4,
    RA_FixedSize = 8,
    RA_MinimumSize = 16,
    RA_MinimumHeight = 32,
    RA_MinimumWidth = 64,
    RA_MaximumSize = 128,
    RA_MaximumHeight = 256,
    RA_MaximumWidth = 512
}ReiszeActions ;




#define DECLARE_RESIZE() \
    void resize(int w, int h);void resize(const QSize &); void setFixedHeight(int w);  \
    void setFixedWidth(int w);void setFixedSize(int w, int h);void setFixedSize(const QSize &s); \
    void setMinimumSize(const QSize &);void setMinimumSize(int minw, int minh); \
    void setMinimumHeight(int minh);void setMinimumWidth(int minw); \
    void setMaximumSize(const QSize &);void setMaximumSize(int maxw, int maxh); \
    void setMaximumHeight(int minh);void setMaximumWidth(int minw);

// 用宏强制覆盖的方法不使用了，因为QSSMainWindow本身已经在event事件内做处理，每个event都重写了，无需再去覆盖。
#define DEFINE_RESIZE(name)\
    void Qss##name::resize(int w, int h){	m_sizeActions |= RA_Resize;	float scale = cale;	m_size = QSize(w, h);Q##name::resize(m_size.width() * scale, m_size.height() * scale);}\
    void Qss##name::resize(const QSize & size){	m_sizeActions |= RA_Resize;	float scale = cale;m_size = size;Q##name::resize(m_size * scale);}\
    void Qss##name::setFixedHeight(int h){m_sizeActions |= RA_FixedHeight;float scale = cale;m_size.setHeight(h);Q##name::setFixedHeight(m_size.height() * scale);}\
    void Qss##name::setFixedWidth(int w){m_sizeActions |= RA_FixedWidth;float scale = cale;m_size.setWidth(w);Q##name::setFixedWidth(m_size.width() * scale);}\
    void Qss##name::setFixedSize(int w, int h){m_sizeActions |= RA_FixedSize;float scale = cale;		m_size = QSize(w, h); this->m_frame->setFixedSize(m_size.width() * scale, m_size.height() * scale)  ; }\
    void Qss##name::setFixedSize(const QSize & size){m_sizeActions |= RA_FixedSize;float scale = cale;	m_size = size;	Q##name::setFixedSize(m_size * scale);}\
    void Qss##name::setMinimumSize(const QSize & size){m_sizeActions |= RA_MinimumSize;float scale = cale;m_minimumSize = size;	Q##name::setMinimumSize(m_minimumSize * scale);}\
    void Qss##name::setMinimumSize(int w, int h){m_sizeActions |= RA_MinimumSize;float scale = cale;	m_minimumSize = QSize(w, h);	Q##name::setMinimumSize(m_minimumSize.width() * scale, m_minimumSize.height() * scale);}\
    void Qss##name::setMinimumHeight(int h){m_sizeActions |= RA_MinimumHeight;float scale = cale;m_minimumSize.setHeight(h);	Q##name::setMinimumHeight(m_minimumSize.height() * scale);}\
    void Qss##name::setMinimumWidth(int w){m_sizeActions |= RA_MinimumWidth;float scale = cale;		m_minimumSize.setWidth(w);	Q##name::setMinimumWidth(m_minimumSize.width() * scale);}\
    void Qss##name::setMaximumSize(const QSize & size){m_sizeActions |= RA_MaximumSize;float scale = cale;	m_maximumSize = size;	Q##name::setMaximumSize(m_maximumSize * scale);}\
    void Qss##name::setMaximumSize(int w, int h){m_sizeActions |= RA_MaximumSize;float scale = cale;	m_maximumSize = QSize(w, h);	Q##name::setMaximumSize(m_maximumSize.width() * scale, m_maximumSize.height() * scale);}\
    void Qss##name::setMaximumHeight(int h){m_sizeActions |= RA_MaximumHeight;float scale = cale;	m_maximumSize.setHeight(h);	Q##name::setMaximumHeight(m_maximumSize.height() * scale);}\
    void Qss##name::setMaximumWidth(int w){m_sizeActions |= RA_MaximumWidth;float scale = cale;	m_maximumSize.setWidth(w);	Q##name::setMaximumWidth(m_maximumSize.width() * scale);}

#define DEFINTE_SCALE_RESIZE(name)\
    if (m_sizeActions.testFlag(RA_FixedWidth)){Qss##name::setFixedWidth(m_size.width() * scale);}\
    if (m_sizeActions.testFlag(RA_FixedHeight)){Qss##name::setFixedHeight(m_size.height() * scale);}\
    if (m_sizeActions.testFlag(RA_FixedSize)){Qss##name::setFixedSize(m_size * scale);}\
    if (m_sizeActions.testFlag(RA_Resize)){	QSize newSize = m_size * scale;if(minimumSize().width() > newSize.width()){name::setMinimumSize(newSize);}name::resize(newSize);}\
    if (m_sizeActions.testFlag(RA_MinimumSize)){Qss##name::setMinimumSize(m_minimumSize * scale);}\
    if (m_sizeActions.testFlag(RA_MinimumHeight)){Qss##name::setMinimumHeight(m_minimumSize.height() * scale);}\
    if (m_sizeActions.testFlag(RA_MinimumWidth)){Qss##name::setMinimumWidth(m_minimumSize.width() * scale);}\
    if (m_sizeActions.testFlag(RA_MaximumSize)){Qss##name::setMaximumSize(m_maximumSize * scale);}\
    if (m_sizeActions.testFlag(RA_MaximumHeight)){Qss##name::setMaximumHeight(m_maximumSize.height() * scale);}\
    if (m_sizeActions.testFlag(RA_MaximumWidth)){ Qss##name::setMaximumWidth(m_maximumSize.width() * scale); }\
    cale = scale;

typedef class ICallDPIChanged
{
    virtual void ScaleChanged(float scale) = 0;
    virtual WId GetWID() const = 0;
    virtual void SetScale(float scale) = 0;
protected:
    uint32_t m_sizeActions;
    float cale = 1;
    QSize m_size;
    QSize m_minimumSize;
    QSize m_maximumSize;
}QssCallDpiChanged;

typedef class IDPIHelper
{
    virtual bool DPIChanged(unsigned short, WId) = 0;
    virtual void RemoveDPIRecord(WId) = 0;//移除指定native窗体的DPI记录 一般用于native窗体析构时
    virtual float GetDPIScale(WId) const = 0;
    virtual float GetOldDPIScale(WId) const = 0;
    virtual QString GetStyleSheet(WId) const = 0;//获取指定DPI下的样式表
    virtual float GetScaleNumber(float, WId) const = 0;//获取指定DPI下的数值 缩放后数值
    virtual QList<WId> GetAllWindowID() const = 0;//获取所有自己加载过皮肤的窗口ID

    //优化接口 主要是为了适配用户主机只有一种DPI时使用
    virtual bool IsOnlyOneDPI() const = 0;//获取用户主机是否只有一种DPI
    virtual void RefrushDPIRecords() = 0;//显示器数量发生了变化 刷新历史显示器DPI记录
    virtual void SetDefaultScale(float scale) = 0;//设置缺省DPI值 当显示器dpi只有一种时刷新
    virtual float GetDefaultScale() const = 0;//获取缺省DPI缩放值 只有当机器上所有的显示器为统一dpi时起作用
}QssDpiHelper;

IDPIHelper * GetDPIHelper();
#define DPIHelper() GetDPIHelper()
class QssPushButton : public QPushButton{
public:
    QssPushButton(QWidget *parent,QString objName);

};

class  QssTtitleBar : public QWidget
{
    Q_OBJECT

signals:
    void OnMaxOrRestore(bool );
public:
    enum QTitleBar_Button
    {
        QTitleBar_Button_Min = 		0x00000001,
        QTitleBar_Button_Max = 		0x00000002,
        QTitleBar_Button_Restore = 	0x00000004,
        QTitleBar_Button_Close = 	0x00000008
    };

    enum QTitleBar_Type
    {
        QTitleBar_Type_MainWindow = QTitleBar_Button_Min |
        QTitleBar_Button_Max |QTitleBar_Button_Restore | QTitleBar_Button_Close,
        QTitleBar_Type_Dialog = QTitleBar_Button_Close,
        QTitleBar_Type_MessageBox = QTitleBar_Button_Close
    };

    QssTtitleBar(QWidget *parent, QTitleBar_Type type = QTitleBar_Type_MainWindow);
    ~QssTtitleBar();

    void setTitle(QString title);
    void setIcon( QIcon icon);

    void setMaxOrRestore(bool val);
    bool maxOrRestore(){return m_maxOrRestore;}
    void SetMainWindow(QMainWindow*);
    QRect& normalRect(){return m_rcNormal;}

private slots:
    void onMaxOrRestore();

protected:
    void paintEvent(QPaintEvent *);
    void mouseMoveEvent(QMouseEvent * ev);
    void mousePressEvent(QMouseEvent * ev);
    void mouseReleaseEvent(QMouseEvent * ev);
    bool eventFilter(QObject * obj, QEvent * ev);

private:
    QPushButton* m_closeBtn;
    QPushButton* m_maxBtn;
    QPushButton* m_restoreBtn;
    QPushButton* m_minBtn;

    QLabel* m_titlebarTitle;
    QMainWindow *m_Main;
    bool m_maxOrRestore;
    bool m_pressed;

    QPoint m_pressedPos;

    QRect m_rcValid;//桌面最大可用尺寸
    QRect m_rcNormal;//还原后窗口尺寸

    QTitleBar_Type m_type;
};
class QssEventFilter
    : public QAbstractNativeEventFilter
{
public:
    virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE
    {/*
        MSG* pMsg = reinterpret_cast<MSG*>(message);
        if(nullptr != pMsg){
            switch (pMsg->message)
            {
                case WM_DPICHANGED:
                {
                    qDebug()<<"DPI CHANGED";

                }
            }
        }*/
        // TODO: filter out or modify msg struct here
        return false;
    }
};

class  QssMainWindow : public QMainWindow,ICallDPIChanged
{
    Q_OBJECT

public slots:
    void OnMaxOrRestore(bool max);
public:
    typedef enum{
        EVENT_MOVE = 523,
    } EVENT_CUSTOM;
    QssMainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0,float scale = 1);
    virtual ~QssMainWindow();

    QWidget *TitleBar();
    void show();
    void showMinimized();
    void showMaximized();
    void showFullScreen();
    void showNormal();
    void setCursorShape(int CalPos)	;
    void setWindowTitle( QString title );
    void setWindowIcon( QIcon icon );
    int CalCursorPos(QPoint pt, int colPos);
    void SetTitleHeight(uint32_t height);
    inline QssTtitleBar* titleBar(){return m_titleBar;}
    inline QFrame* frame(){return m_frame;}
        int CalCursorCol(QPoint pt);    //计算鼠标X的位置
    virtual bool eventFilter(QObject * obj, QEvent * ev);
    bool nativeEvent(const QByteArray &eventType, void *message, long *result);

private:
    void onMouseMoveEvent(QMouseEvent * ev);
    void onMousePressEvent(QMouseEvent * ev);
    void onMouseReleaseEvent(QMouseEvent * ev);
protected:
    QFrame* m_frame;
    QRect mFrameRect;
    QRect mRect;
    QRect m_CentralRect;
    QssTtitleBar* m_titleBar;
    void showEvent(QShowEvent *ev);

    virtual void ScaleChanged(float scale) ;
    virtual WId GetWID() const;
    virtual void SetScale(float scale) ;
private:

    QRect m_rcValid;//桌面最大可用尺寸
    QRect m_rcNormal;//还原后窗口尺寸
    QRect m_rcNormalCentral;//还原后central widget的尺寸

    /**  边框调整大小相关 */
    QPoint m_pos;
    bool m_mousePressedInBoundy;
    bool m_left,m_right,m_top,m_bottom;


    int     m_iCalCursorPos;
    bool    m_bLeftPress;
    QRect   m_rtPreGeometry;
    QPoint  m_ptViewMousePos;
    float   m_scale;
};

class  QssDialog : public QDialog
{
    Q_OBJECT

public:
    QssDialog(QWidget *parent);
    virtual ~QssDialog();

    void show();
    void raise();
    void activateWindow();

    int exec();

    void setWindowTitle( QString title );
    void setWindowIcon( QIcon icon );

    inline QssTtitleBar* titleBar(){return m_titleBar;}
    inline QFrame* frame(){return m_frame;}

    virtual bool eventFilter(QObject * obj, QEvent * ev);

private:
    void onMouseMoveEvent(QMouseEvent * ev);
    void onMousePressEvent(QMouseEvent * ev);
    void onMouseReleaseEvent(QMouseEvent * ev);

private:
    QWidget* m_parent;

    QFrame* m_frame;
    QssTtitleBar* m_titleBar;

    QRect m_rcValid;

    /**  边框调整大小相关 */
    QRect mFrameRect;
    QPoint m_pos;
    bool m_mousePressedInBorder;
    bool m_left,m_right,m_top,m_bottom;

};


// 可停靠widget
class  QssDockWidget : public QDockWidget
{
    Q_OBJECT

public:
    QssDockWidget(QWidget *parent);
    virtual ~QssDockWidget();

    void show();
    void raise();
    void activateWindow();

    int exec();

    void setWindowTitle( QString title );
    void setWindowIcon( QIcon icon );
    void paintEvent(QPaintEvent *);
    inline QssTtitleBar* titleBar(){return m_titleBar;}
    inline QFrame* frame(){return m_frame;}

    virtual bool eventFilter(QObject * obj, QEvent * ev);

private:
    void onMouseMoveEvent(QMouseEvent * ev);
    void onMousePressEvent(QMouseEvent * ev);
    void onMouseReleaseEvent(QMouseEvent * ev);

private:
    QFrame* m_frame;
    QssTtitleBar* m_titleBar;

    QRect m_rcValid;
    QWidget* m_parent;

    /**  边框调整大小相关 */
    QRect mFrameRect;
    QPoint m_pos;
    bool m_mousePressedInBorder;
    bool m_left,m_right,m_top,m_bottom;

};

class  QssMessageBox : public QMessageBox
{
    Q_OBJECT

public:
    explicit QssMessageBox(QWidget *parent = 0);
    QssMessageBox(Icon icon, const QString &title, const QString &text,
        StandardButtons buttons = NoButton, QWidget *parent = 0,
        Qt::WindowFlags flags = Qt::Widget | Qt::FramelessWindowHint);
    ~QssMessageBox();

    inline QssTtitleBar* titleBar(){return m_titleBar;}
    inline QFrame* frame(){return m_frame;}

    static QMessageBox::StandardButton tips(const QString & text, QWidget* parent = 0,
        const QString & title = QString::fromLocal8Bit("提示"), StandardButtons btn = QMessageBox::Ok);
    static QMessageBox::StandardButton warn(const QString & text, QWidget* parent = 0,
        const QString & title = QString::fromLocal8Bit("警告"), StandardButtons btn = QMessageBox::Ok);
    static QMessageBox::StandardButton error(const QString & text, QWidget* parent = 0,
        const QString & title = QString::fromLocal8Bit("错误"), StandardButtons btn = QMessageBox::Ok);
    static QMessageBox::StandardButton ask(const QString & text, QWidget* parent = 0,
        const QString & title = QString::fromLocal8Bit("询问"), StandardButtons btn = QMessageBox::Yes | QMessageBox::No);

    /** 覆盖定义，适配原有QMessageBox */
    static StandardButton information(QWidget *parent, const QString &title,
        const QString &text, StandardButtons buttons = Ok,
        StandardButton defaultButton = NoButton);
    static StandardButton question(QWidget *parent, const QString &title,
        const QString &text, StandardButtons buttons = QMessageBox::Ok,
        StandardButton defaultButton = QMessageBox::NoButton);
    static StandardButton warning(QWidget *parent, const QString &title,
        const QString &text, StandardButtons buttons = QMessageBox::Ok,
        StandardButton defaultButton = QMessageBox::NoButton);
    static StandardButton critical(QWidget *parent, const QString &title,
        const QString &text, StandardButtons buttons = QMessageBox::Ok,
        StandardButton defaultButton = QMessageBox::NoButton);

    static QMessageBox::StandardButton regard(const QString & text, QWidget* parent = 0,
        const QString & title = QString::fromLocal8Bit("关于"));
    static QMessageBox::StandardButton regard(const QString & text, QIcon icon, QWidget* parent = 0,
        const QString & title = QString::fromLocal8Bit("关于"));

    static QMessageBox::StandardButton regardQt(QWidget* parent = 0,
        const QString & title = QString::fromLocal8Bit("关于Qt"));

    static void about(QWidget *parent, const QString &title, const QString &text);
    static void about(QWidget *parent, const QString &title, const QString &text, QIcon icon);

    static void aboutQt(QWidget *parent, const QString &title = QString());

    bool eventFilter(QObject * obj, QEvent * ev);

private:
    QFrame* m_frame;
    QssTtitleBar* m_titleBar;
    QWidget* m_parent;

    QRect m_rcValid;
};



class QssMaskWidget : public QWidget
{
    Q_OBJECT

public:
    QssMaskWidget(QWidget *parent = Q_NULLPTR);
    virtual ~QssMaskWidget();
    virtual bool eventFilter(QObject * obj, QEvent * ev);

public:

protected:
    virtual void paintEvent(QPaintEvent *event);

private:
    QWidget *mParent;
    Ui::Toast ui;
};

class QssToastWidget : public QWidget
{
    Q_OBJECT

public:
    QssToastWidget(QWidget *parent = Q_NULLPTR);
    ~QssToastWidget();

    void setText(const QString& text);

    void showAnimation(int timeout = 2000);// 动画方式show出，默认2秒后消失

public:
    // 静态调用
    static void showTip(const QString& text, QWidget* parent = nullptr);

protected:
    virtual void paintEvent(QPaintEvent *event);

private:
    Ui::Toast ui;
};



class QSSProcessBar : public QDialog
{
    Q_OBJECT

public:
    explicit QSSProcessBar(QWidget *parent = nullptr);
    ~QSSProcessBar();
    void showEvent(QShowEvent *) override;

public slots:
    void on_percent(int);
    void on_done_close();
private:
    Ui::Process *ui;
    QWidget *mParent;
};


#define tipBox(text)   	QssMessageBox::tips(text)
#define warnBox(text)  	QssMessageBox::warn(text)
#define errBox(text)	QssMessageBox::error(text)
#define askBox(text)   	QssMessageBox::ask(text)

#define aboutBox(title, text)	QssMessageBox::regard(text, 0,title)
#define aboutQtBox()			QssMessageBox::regardQt()

#endif // QSS_H
